-
Notifications
You must be signed in to change notification settings - Fork 123
add support for redirect limits #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some small suggestions and questions
/// Redirects are not followed. | ||
case disallow | ||
/// Redirects are followed with a specified limit. Cycle detection reqiures that all visited URL's are kept in memory. | ||
case allow(max: Int, allowCycles: Bool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "disable" and "enable" seem more natural than "disallow" and "allow"? since this is a feature flag not a security policy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this struct was renamed to Policy
, do you think RedirectPolicy.enable
is better than RedirectPolicy.allow
? I don't have a strong opinion here, wdyt? cc @ianpartridge
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the tests it reads as redirects: .allow(max: 5, allowCycles: false)
which seems fine (although I would prefer redirection:
instead of redirects:
). .allow
makes sense to me because redirection is something that is requested by the remote HTTP server via an HTTP return code, and we decide whether to allow it or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about RedirectConfiguration.disallow
and RedirectConfiguration.follow
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like .follow
🙂
@@ -423,6 +427,19 @@ extension HTTPClient.Configuration { | |||
self.read = read | |||
} | |||
} | |||
|
|||
/// Specifies redirect processing settings. | |||
public enum RedirectPolicy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! What do people think about calling this RedirectConfiguration
to match TLSConfiguration
etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 from me, @tomerd wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
/// Redirects are not followed. | ||
case disallow | ||
/// Redirects are followed with a specified limit. Cycle detection reqiures that all visited URL's are kept in memory. | ||
case allow(max: Int, allowCycles: Bool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the tests it reads as redirects: .allow(max: 5, allowCycles: false)
which seems fine (although I would prefer redirection:
instead of redirects:
). .allow
makes sense to me because redirection is something that is requested by the remote HTTP server via an HTTP return code, and we decide whether to allow it or not.
XCTAssertThrowsError(try httpClient.get(url: "https://localhost:\(httpBin.port)/redirect/infinite1").wait(), "Should fail with redirect limit") { error in | ||
XCTAssertEqual(error as! HTTPClientError, HTTPClientError.redirectLimitReached) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want to test case insensitive loops?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean when schema and path are capitalised differently?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks really good, two suggestions, most importantly, we shouldn't make the policy enum public.
/// Default client timeout, defaults to no timeouts. | ||
public var timeout: Timeout | ||
/// Upstream proxy, defaults to no proxy. | ||
public var proxy: Proxy? | ||
/// Ignore TLS unclean shutdown error, defaults to `false`. | ||
public var ignoreUncleanSSLShutdown: Bool | ||
|
||
public init(tlsConfiguration: TLSConfiguration? = nil, followRedirects: Bool = false, timeout: Timeout = Timeout(), proxy: Proxy? = nil) { | ||
self.init(tlsConfiguration: tlsConfiguration, followRedirects: followRedirects, timeout: timeout, proxy: proxy, ignoreUncleanSSLShutdown: false) | ||
public init(tlsConfiguration: TLSConfiguration? = nil, redirects: RedirectPolicy = .allow(max: 5, allowCycles: false), timeout: Timeout = Timeout(), proxy: Proxy? = nil) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's quite a lot of code duplication here, with each initializer having the same hard-coded .allow(max: 5, allowCycles: false)
default value. We should pull that out into a separate
static let defaultRedirectPolicy: RedirectPolicy = .allow(max: 5, allowCycles: false)
then this can be:
public init(tlsConfiguration: TLSConfiguration? = nil, redirects: RedirectPolicy = HTTPClient.defaultRedirectPolicy, timeout: Timeout = Timeout(), proxy: Proxy? = nil) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then defaultRedirectPolicy
would also have to be public, what if it will be optional instead?
Co-Authored-By: Johannes Weiss <[email protected]>
|
@weissi I rewrote the backpressure, could you please take a look at a comment to see if it makes sense? |
@artemredkin cool, looks good! On top of the test with actual channels, did the |
ping @artemredkin on the above question |
@weissi not yet, do you think its critical? we have "integration-style" test for backpressure for now |
@artemredkin I think it would be good to have both especially given that the integration test might turn out to not be a 100% reliable (I think it is but hard to tell for sure). I also think the integration test will be much easier to follow for people who aren't you & me because we worked on that integration test together. |
@artemredkin perfect, no, let’s not block 1.0.0 |
@weissi @Lukasa @tomerd @ianpartridge any additional comments? |
None from me. |
LGTM. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks! LGTM
This PR adds support for 2 types of redirect limits - one that detects loops (by keeping history of all visited URL's for a single request), and one that just counts the number of redirects.
fixes #76